package topt_12z.general;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import topt_12z.interfaces.SynchronizeEventInterface;
import topt_12z.logging.IO;
import topt_12z.network.Node;
import topt_12z.statistics.SimulationStatistics;

public class NetworkSynchronizer {
	private Logger log;
	private SimulationStatistics stats = null;
	ArrayList<ArrayList<Node>> networkGrid = null;
	
	private List<SynchronizeEventInterface> synchronizeEventListenerList = new ArrayList<SynchronizeEventInterface>();
	private static NetworkSynchronizer instance;

	private int currentTime = 0;

	private NetworkSynchronizer() throws Exception {
		log=IO.getInstance().getLogger();
		stats = SimulationStatistics.getInstance();
	}

	public static NetworkSynchronizer getInstance() throws Exception {
		if (instance == null) {
			instance = new NetworkSynchronizer();
		}
		return instance;
	}

	/**
	 * startuje symulacje - zaczyna liczyc czas i wysylac zadania obsluzenia
	 * kolejnych pakietow
	 */
	public void start() {
		log.fine("Entering");
		while (currentTime < Globals.SIMULATION_TIME) {
			log.finest("current time: " + currentTime);
			// zrob cos
			for(SynchronizeEventInterface worker : synchronizeEventListenerList){
				log.finest("worker: " + worker);
				worker.handleSynchronizeEvent();
			}
			currentTime++;
		}
		
		countNotFinishedPackets();
		logStats();
	}
	
	public void reset(){
		if(stats!= null) stats.reset();
		instance = null;
	}
	
	private void countNotFinishedPackets(){
		for (int row = 0; row < networkGrid.size(); row++) {
			ArrayList<Node> rowList = networkGrid.get(row);
			for (int col = 0; col < rowList.size(); col++) {
				Node tempNode = rowList.get(col);
				if(!tempNode.getBuffer().isEmpty()){
					stats.addToNotFinishedCounter(tempNode.getBuffer().size());
					tempNode.getBuffer().clear();
				}else{
					//nic
				}
			}
		}
	}
	
	private void logStats(){
		log.info("ilosc straconych pakietow przez timeout: " + stats.getTimeoutCounter());
		log.info("ilosc straconych pakietow przez koniec sym: " + stats.getNotFinishedCounter());
		log.info("ilosc straconych pakietow przez przepelnienie bufora: " + stats.getLostBufferFull());
		log.info("suma straconych pakietow: " + (stats.getLostBufferFull() + stats.getNotFinishedCounter()+stats.getTimeoutCounter()));
		log.info("ilosc przetworzonych pakietow: " + (stats.getLostBufferFull() + stats.getNotFinishedCounter()+stats.getTimeoutCounter() + stats.getReceivedPacketsCounter()));
	}

	public synchronized void addSynchronizeEventListener(
			SynchronizeEventInterface listener) {
		synchronizeEventListenerList.add(listener);
	}

	public synchronized void removeSynchronizeEventListener(
			SynchronizeEventInterface listener) {
		synchronizeEventListenerList.remove(listener);
	}

	public List<SynchronizeEventInterface> getSenders() {
		return synchronizeEventListenerList;
	}

	public int getCurrentTime() {
		return currentTime;
	}
	
	public void setNetworkGrid(ArrayList<ArrayList<Node>> _networkGrid){
		this.networkGrid = _networkGrid;
	}
	
	public ArrayList<ArrayList<Node>> getNetworkGrid(){
		return this.networkGrid;
	}
}
